package edu.put.sk.nrpp.ospf.packet.lsa;

import java.net.InetAddress;
import java.net.UnknownHostException;

import edu.put.sk.nrpp.*;

/**
 * 
 * A.4.1 The LSA header (RFC 2328)
 *   All LSAs begin with a common 20 byte header.  This header contains
 *   enough information to uniquely identify the LSA (LS type, Link State
 *   ID, and Advertising Router).  Multiple instances of the LSA may
 *   exist in the routing domain at the same time.  It is then necessary
 *   to determine which instance is more recent.  This is accomplished by
 *   examining the LS age, LS sequence number and LS checksum fields that
 *   are also contained in the LSA header.
 *   <pre>


 *        0                   1                   2                   3
 *        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *0  0   |            LS age             |    Options    |    LS type    |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *1  32  |                        Link State ID                          |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *2  64  |                     Advertising Router                        |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *3  96  |                     LS sequence number                        |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *4  128 |         LS checksum           |             length            |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *</pre>
 * description from RFC 2328
 * @author kevin
 */

abstract public class LSA {
	protected Bit[] _data;
	
	public static LSA getInstance(Bit[] data) throws Exception{
		int type=Bit.toInt(Bit.cut(data, 24, 31));
		if(type==1){
			return new LSAType1(data);
		}
		else if(type==2){
			return new LSAType2(data);
		}
		else if(type==3){
			return new LSAType3(data);
		}
		else if(type==4){
			return new LSAType4(data);
		}
		else if(type==5){
			return new LSAType5(data);
		}
		else if(type==6){
			return new LSAType6(data);
		}
		else if(type==7){
			return new LSAType7(data);
		}
		else
			return null;
		
	}
	
	protected LSA(Bit[] data) throws Exception{
		this._data=data;
		int dataLen=this._data.length;
		int exceptedLen=getLength()*8;
		if(dataLen<exceptedLen)
			throw new Exception("LSA wrong length excepted: "+ exceptedLen+" given: "+dataLen);
	}
	
	
	/**
	 * LS age
     * The time in seconds since the LSA was originated.
	 * @return LS age (in sec)
	 */
	public int getLSAge(){
		return Bit.toInt(Bit.cut(_data, 0, 15));
	}
	/**
	 * The optional capabilities supported by the described portion of
     * the routing domain.  OSPF's optional capabilities are documented
     * in Section A.2.
	 * @return header options
	 */
	public Bit[] getHeaderOptions(){
		return Bit.cut(_data, 16, 23);
	}
	
	/**
	 * The type of the LSA.  Each LSA type has a separate advertisement
     *   format.  The LSA types defined in this memo are as follows (see
     *   Section 12.1.3 for further explanation):
     *   <pre>
     *   LS Type   Description
     *   ___________________________________
     *   1         Router-LSAs
     *   2         Network-LSAs
     *   3         Summary-LSAs (IP network)
     *   4         Summary-LSAs (ASBR)
     *   5         AS-external-LSAs
     *   </pre>
	 * @return LS type
	 */
	public int getLSType(){
		return Bit.toInt(Bit.cut(_data, 24, 31));
	}
	
	/**
	 * This field identifies the portion of the internet environment
     * that is being described by the LSA.  The contents of this field
     * depend on the LSA's LS type.  For example, in network-LSAs the
     * Link State ID is set to the IP interface address of the
     * network's Designated Router (from which the network's IP address
     * can be derived).  The Link State ID is further discussed in
     * Section 12.1.4.
	 * @return Link State Id
	 */
	public InetAddress getLinkStateId(){
		try {
			return Bit.toInetAddres(Bit.cut(_data, 32, 63));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	
	/**
	 * The Router ID of the router that originated the LSA.  For
     * example, in network-LSAs this field is equal to the Router ID of
     * the network's Designated Router.
	 * @return Advertising Router
	 */
	public InetAddress getAdvertisingRouter(){
		try {
			return Bit.toInetAddres(Bit.cut(_data, 64, 95));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Detects old or duplicate LSAs.  Successive instances of an LSA
     * are given successive LS sequence numbers.  See Section 12.1.6
     * for more details.
	 * @return LS Sequence Number
	 */
	public int getLSSequenceNumber(){
		return Bit.toInt(Bit.cut(_data, 96, 127));
	}
	
	/**
	 * The Fletcher checksum of the complete contents of the LSA,
     * including the LSA header but excluding the LS age field. See
     * Section 12.1.7 for more details.
	 * @return checksum
	 */
	public int getLSCheckSum(){
		return Bit.toInt(Bit.cut(_data, 128, 143));
	}
	
	/**
	 * The length in bytes of the LSA.  This includes the 20 byte LSA
     * header.
	 * @return length
	 */
	public int getLength(){
		return Bit.toInt(Bit.cut(_data, 144, 159));
	}
	
}
